//
//  OtherVC.swift
//  ReviewSwift
//
//  Created by ladystyle100 on 2017/8/23.
//  Copyright © 2017年 WangXQ. All rights reserved.
//

import UIKit

/** 遵守UITableViewDelegate协议 */
class BaseVC: UIViewController, UITableViewDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        /** Swift中可以不写 ; 结束符号
         *  并且调用属性方法等等, 都是 . 点语法
         *  Array, Dictionary, Int, Float.....等等, 都是结构体了
         *  Foundation框架部分类去掉了NS, 比如Date, URL.....
         *  Any相当于任何值, 对, 连基本数据都是
         *  值名可以用中文
         */
        
        /** 模块
         *  那么什么样才能成为一个模块呢？一个App就是一个模块，一个第三方API, 第三等方框架等都是一个完整的模块
         */
        
        /** 一些修饰和标志
         *  open: 任何地方可以继承, Override
         *  public: 修饰的 class 在模块内部可以访问和继承, 修饰的 func 在模块内部可以被访问和重载（override）,在外部只能访问
         *  internal: 默认权限, 模块内部可以访问，超出模块内部就不可被访问了。
         *  final: 修饰的 class 任何地方都不能不能被继承, 修饰的 func 任何地方都不能被 Override
         *  fileprivate: 文件域私有(比如当前是BaseVC.swift文件, 如果在ViewController.swift文件内就调用不了)
         *  private: 当前作用域可用
         *  lazy: 初始化懒惰性(声明懒加载需要这个标志)
         *  static: 类函数(可以看成默认的函数都是, OC的 -(void)aaa, 加了就变成 +(void)aaa)
         *  @objc: 可以作为事件的函数(如btn点击事件, 通知时间....), 表示使用它的类都继承自 NSObject
         */
        
        /** 常见编译告警, Swift里面很多告警只是让你注意语法
         *  未使用值: Initialization of immutable value 'a' was never used; consider replacing with assignment to '_' or removing it
         *  该变量只写未读: Variable 'b' was written to, but never read
         *  该变量只读未写A: Variable 'b' was never mutated; consider changing to 'let' constant
         *  返回值没有接受: Result of call to 'sorted()' is unused
         */
        
        /** block, 这边都称为闭包 */
        
        /** 获取class */
        //ViewController.classForCoder()
        
        /** weak声明, 必须用var */
        weak var weakSelf = self
        print(weakSelf)
    }
    
    /** 结构体, Swift的一等公民🙄 */
    struct WXQ {
        var a: Int
        var b: String?
        var c: Base?
    }
    
    /** 结构体 */
    enum House: String {
        /** 建议和官方一直, 第一个字母小写, 其实就相当一个属性来看待, 类的属性 */
        case wang = "a"
        case xing = "b"
    }
    
    // 存储属性
    var calculations_ = 10 {
        // 监察属性的set
        willSet {
            
        }
        didSet {
            // 旧的值
            //oldValue
        }
    }
    // 计算属性, 如果只声明 get, 那么就是只读
    var calculations: Int {
        get {
            if calculations_ >= 10 {
                return calculations_
            }
            
            return 0
        }
        set {
            if newValue >= 10 {
                calculations_ = newValue
            }
        }
    }
    
    /** 懒加载
     *  lazy var 值名: 类名 = {}()闭包
     *  只能是var, 不能是let, 因为是懒加载, 是后面用到的时候, 调用闭包赋值的, let就表示不能改变值了
     *  这个最糟糕的就是在block里面不能联想外面的self了, 基本都得硬敲
     *  注意, 这里的懒加载和OC是两个概念
     *  OC: 每次取值的时候判断是否为nil
     *  Swift: 只会运行一次
     */
    private lazy var customNav: UIView = {
        print("只会运行一次")
        let customNav = UIView(frame: CGRect.init(x: 0, y: 0, width: 0, height: 0))
        return customNav
    }()
    
    /** 完整一个函数, 这里的返回值不再像OC一样单一, 可以返回一个函数, 元组....
    定义 func 函数名(参数) -> 返回值 { 代码 }
    private func <#name#>(<#parameters#>) -> <#return type#> {
        <#function body#>
    }
     */
    
    /** 常变量 */
    private func letVar() {
        // let 常量: 只能读取
        // var 变量: 可读可写
        // 如果某个值只读没写, 最好用let, 因为保证数据安全, 线程安全等等
        let a = 1
        var b = 0
        //a = 2 编译报错
        b = 3
        
        // C的自增已被移除
        //b++
        b += 1
        
        
        /** 在类后面加 !是表示这个值一定存在, ?则是不一定存在 */
        //var btn: UIButton!
        
        /** 如果直接等于某值, 类型系统会自己判断 */
        //var a = 1
        
        /** 强转类型 as! 类名 */
        //let a = 1
        //let b: CGFloat = a as! CGFloat
    }
    
    /** 字符串 */
    private func str() {
        /** 新特性
         *  可以运用 + - = 运算
         *
         */
        // 是否为空, ""这样也算空
        var str = "str"
        print(str.isEmpty)
        
        /** 获取字符串长度 */
        str.lengthOfBytes(using: .utf8)
        
        // 可用 + 或 += 符号进行拼接字符串
        str += "111"
        
        /** 可用中文和Emoji来做值名 */
        let 名字 = "🙄wxq"
        let 😆 = "表情"
        print(名字, 😆)
        
        /** Int转字符串 */
        print(String.init(1000))
        
        /** float转字符串 */
        print(String.init(stringInterpolationSegment: 0.3))
        
        /** bool转字符串 */
        print(String.init(stringInterpolationSegment: true))
        
        /** data转字符串 */
        //String.init(data: <#T##Data#>, encoding: <#T##String.Encoding#>)
        
        /** 可以字符串里面进行拼接 */
        var combination = "第一个\(str), 第二个\(名字), 第三个\(😆)"
        print(combination)
        
        /** 添加字符串 */
        combination.append("a".characters.first!)
        combination.append("b")
        // 不改变自身
        let resultStr = combination.appending("c")
        print(resultStr, combination)
        
        /** String.Index
         *  我觉得这个和 Range 是差不多的 (location, length)
         */
        //resultStr.index(after: <#T##String.Index#>)
        //resultStr.index(before: <#T##String.Index#>)
        
        var insertStr = ""
        /** 插入单个字符串 */
        insertStr.insert("单".characters.first!, at: combination.index(insertStr.startIndex, offsetBy: 0))
        print(insertStr)
        /** 插入多个字符串 */
        insertStr.insert(contentsOf: "多个".characters, at: combination.index(insertStr.startIndex, offsetBy: 0))
        print(insertStr)
        
        /** 字符串截取 */
        var subStr = "qwertyuiop"
        subStr.substring(to: subStr.index(subStr.startIndex, offsetBy: 3))
        subStr.substring(with: subStr.index(subStr.endIndex, offsetBy: -6)..<subStr.endIndex)
        
        /** 删除字符串 */
        subStr.removeAll()
        
        /** 替换字符串 */
        subStr.replacingOccurrences(of: "aa", with: "bb")
        
        /** 获取这个字符串在某个字符串的范围 */
        let rangeStr = "tyu"
        subStr.range(of: rangeStr)
        
        /** 获取大写字符串 */
        rangeStr.uppercased()
        
        /** 获取小写字符串 */
        rangeStr.lowercased()
        
        /** 字符串比较 ==, >=, <=, >, < */
        let result = rangeStr == rangeStr
        print(result)
        
        /** 前缀 */
        rangeStr.hasPrefix("aa")
        
        /** 后缀 */
        rangeStr.hasSuffix("bb")
        
    }
    
    /** 数组 */
    private func arr() {
        /** 新特新
         *  存储的值不局限于OC了, 可以直接存储 Int, float等等...
         *  一般arr都默认会是同一个类型, 如果要装很多种类型的值, 需要特别标志类型
         *  var aaaa: [Any]
         *  var bbbb = ["a", 1, ["3": 2]] as! [Any]
         *  可以用 +, 直接两个加, 但注意, 两个类型必须一致
         *  == 相比较两个数组
         *  提供判断是否为空, 翻转, 正逆序等等接口
         */
        
        var array = ["xpp", "ddd", "wwww", "AcA", "aab"]
        
        /** 添加 */
        array.append("1")
        
        /** 插入 */
        array.insert("ss", at: 3)
        
        /** 删除元素, 返回被删除的值 */
        let _ = array.remove(at: 1)
        
        /** 是否为空 */
        array.isEmpty
        
        /** 是否相等 */
        array == ["aaa"]
        
        /** 是否包含某元素 */
        array.contains("ddd")
        
        /** 翻转 */
        array.reverse()
        
        /** 排序 */
        // 正序
        let justArr = array.sorted()
        // 逆序
        let againstArr = array.sorted(by: >)
        print("arr = \(justArr), aArr = \(againstArr)")
        
        var oneArr = ["1", "2"]
        /** +号, 两个数组相加 */
        let _ = array + oneArr
        
        /** map 用block映射arr
         *  return 会组成一个数组, 返回出去, 数组里面的类型, 值, 可以自己随意定制
         */
        let arr = [1, 2, 4, 2, 3, 5]
        let _ = arr.map { (a) -> String in
            print(a)
            return "1"
        }
        
    }
    
    /** 字典 */
    private func dic() {
        /** 新特性
         *  存储的值不局限于OC了, 可以直接存储 Int, float等等...
         *  key的值也是, 可以是Int, float等等
         */
        
        /** key只能是某一个类型, value可以是任何类型 */
        //var dic: [Int: Any] = [1: "aa"]
        var dic = [1: "aa"]
        print(dic[1]!)
        
        /** 添加和修改值 */
        dic[2] = "bb"
        
        /** 删除某个值, 并且返回被删除的值 */
        dic.removeValue(forKey: 1)
        
        //dic.updateValue("aa", forKey: 2)
        
        /** 获取字典的keys or values */
        dic.keys
        dic.values
        
        /** 值个数 */
        dic.count
        
        /** 是否为空 */
        dic.isEmpty
        
        /** map 用block映射dic
         *  return 会组成一个数组, 返回出去, 数组里面的类型, 值, 可以自己随意定制
         */
        let arr = dic.map { (key, value) -> (name: String, age: Int) in
            print(key, value)
            return ("1", 2)
        }
        print(arr)
        
    }
    
    /** 元组 */
    private func tuple() -> (name: String, age: CGFloat, gender: String) {
        // 两种声明, 建议第一种
        let people = (name: "wxq", age: CGFloat(21), gender: "男 ")
        //let (name, age, gender) = ("pdm", 21, "女")
        
        /** 打印值 */
        print("people = \(people), name = \(people.name)")
        
        // 作为返回值, 这样可以返回多个类型的值了, 虽然字典也能做到, 但总是不够这个来的方便
        return people
    }
    
    /** if判断 */
    private func xqIf() {
        var a: Base?
        
        // 这个就是平常网上说的解包~, What???什么鬼, 就是判断一下是否存在好不好？为什么要说成那么难理解, SB
        if let b = a {
            
        }
        
        
        var one: Int?
        var two: Int?
        
        // 两个值都存在, 并且a > b
        if let a = one, let b = two, a > b {
            print("one > two")
        }
        
    }
    
    /** switch选择 */
    private func xqSwitch() {
        let i = "a"
        
        /** 新特性
         *  判断字符串, 范围性判断, 多个判断
         *  默认添加break, 如需运行多个, 添加fallthrough
         *  如果没写满所有条件的情况下, 必须保留default(比如一个枚举, 只有3个选项, 如果全部都写了, 那default就可以去除)
         *  每个case和default, 都必要要有代码存在
         */
        switch i {
        case "a":
            print("条件符合")
            
            fallthrough
            print("我并不会执行")
            
        case "b", "c", "d", "5", "6":// 复合匹配
            print("因为上一个条件符合并且加了 fallthrough, 所以我也会执行")
            
            // 如果存在
        case let x:
            print("字符是 \(x)")
            
        default:
            print("")
        }
        
        
        let a = 5
        switch a {
        case 0, 2, 3:// 复合匹配
            print(a)
        case 9..<6:// 区间匹配
            print(a)
        default:
            print(a)
        }
        
        // 判断元组
        let tuple = (1, "3")
        switch tuple {
        case (2, "5"):
            print("")
        case (5...10, "2"):
            print("")
        case (1, "2"), (5, "6"), (0, "y"):
            print("")
        default:
            print("")
        }
        
    }
    
    /** for循环 */
    private func xqFor() {
        // for ( ; ; ) {} 这种写法已被移除
        
        /**
         *  0..<3 小于,  0, 1, 2
         *  0...3 等于,  0, 1, 2, 3
         *  3..>0 大于,  3, 2, 1
         */
        
        /** for 值 in 循环条件 {} */
        for i in 0..<3 {
            print("i = \(i)")
        }
        
        /** 相反循环 */
        for i in (0..<3).reversed() {
            print(i)
        }
        
        /** 循环字符串 */
        let str = "Hello world"
        for cha in str.characters {
            print("cha = \(cha)")
        }
        
        /** 循环数组 */
        let array = [1, 5, 3, 2, 4]
        for (index, value) in array.enumerated() {
            print("index = \(index), value = \(value)")
        }
        
        /** 循环字典 */
        let dic = ["name": "wxq", "gender": "男"]
        for (key, value) in dic.enumerated() {
            print("key = \(key), value = \(value)")
        }
        
        /** 闭包循环 */
        (1...10).forEach { (i) in
            print("\(i)")
        }
        
        /** 相当于do {} while() */
        var a = 20
        repeat {
            print("a = \(a)")
        }while a <= 10
        
        /** while */
        while a <= 30 {
            print("a = \(a)")
            a = 40
        }
        
    }
    
    /** guard警卫 */
    private func xqGuard() {
        let a = 0
        // 其实我觉得和if没太大区别, 不过里面一定要加return, continue等字眼
        guard a == 1 else {
            print("a不等于1")
            return
        }
        
    }
    
    /** doCatch语法 */
    private func doCatch() {
        //try
        
        // do-catch 处理错误
        /*
        do {
            try <expression>
            <无错误>
        } catch <error case> {
        <错误处理>
        } catch <error case> where <错误限定条件> {
        <错误处理>
        } catch {
        <不被前面条件捕获的错误处理>
        }
         */
    }
    
    /** 线程 */
    private func thread() {
        // 平常OC用的, 回到主队列执行
        DispatchQueue.main.async { }
        
        // 主队列异步延迟3秒执行
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { }
        
        // global队列
        DispatchQueue.global().async { }
        
        // 自创队列
        DispatchQueue.init(label: "hahah").async { }
        
        
        
        // 这个要声明成全局变量, 不要让系统释放了, 释放了就取消掉任务了
        var timerSource: DispatchSourceTimer!
        /** 创建计时器
         *  flags 标志
         *  queue 任务执行队列
         */
        timerSource = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags.strict, queue: DispatchQueue.global())
        
        /** 配置
         *  deadline 开始时间
         *  interval 间隔
         *  leeway 误差
         */
        timerSource.scheduleRepeating(deadline: DispatchTime.now(), interval: 1, leeway: DispatchTimeInterval.seconds(0))
        
        /** 注册完成 */
        timerSource.setRegistrationHandler {
            print("setRegistrationHandler = ", Date.init())
        }
        
        /** 间隔执行 */
        timerSource.setEventHandler {
            print("setEventHandler = ", Date.init())
        }
        
        /** 取消执行 */
        timerSource.setCancelHandler {
            print("setCancelHandler = ", Date.init())
        }
        
        /** 启动任务 */
        timerSource.resume()
        
        /** 暂停任务 */
        //timerSource.suspend()
        
        /** 取消任务 */
        //timerSource.cancel()
        
    }
    
}


class Base: NSObject {
    var a = 1
}














